home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Collection of Tools & Utilities
/
Collection of Tools and Utilities.iso
/
pascal
/
memmap.zip
/
MEMMAP.TXT
< prev
Wrap
Text File
|
1989-07-08
|
13KB
|
292 lines
MemMap: Map of DOS Memory Blocks
Using Turbo Pascal 5.0
by
Earl F. Glynn
Overland Park, KS
CompuServe 73257,3527
(C) Copyright 1989, All Rights Reserved.
Introduction
------------
MemMap is a DOS utility that displays all allocated memory blocks,
including terminate-and-stay-resident (TSR) programs and their
associated environment memory blocks. With a /V switch, MemMap
displays the variables in each environment block.
MemMap has been tested with DOS 2.10, 3.3, 4.0 and OS/2 Extended Edition
1.1 DOS Command subset.
The original motivation for writing MemMap was to determine the amount
of memory lost to needless environment variables being saved every time
a TSR was loaded into memory. But several other factors shaped the
development of MemMap:
- DOS 4.0 "MEM /DEBUG" functionality is not present in DOS 3.X.
Some utilities, such as PC Magazine's PCMAP, give part of the
information desired about TSRs.
- PCMAP returns "unknown" for most program names when run under
DOS 4.0 (See Figure 1). Since MEM is a new command under
DOS 4.0, and cannot be run on earlier DOS versions, a common
program that operates under both DOS 3.X and 4.X is desirable.
- DOS 4.0 MEM reports block sizes only in hexadecimal bytes, e.g.,
Sidekick (SKM) is hex 7180 bytes long, instead of decimal
29056 bytes.
- PCMAP aggregates both environment and program blocks, creating
two problems: (1) the memory entries are not always listed
in ascending order; (2) size information about individual
environment blocks is not available.
- The size and contents of the environment blocks cannot be
effectively managed without an easy way to display all variables
in all environment blocks.
- Several memory map programs have erratic behavior when IBM's
Workstation Program (INDCIPL.EXE) and Expanded Memory
Manager (INDXMAA.SYS) are in memory.
- Turbo Pascal can be used to write system utilities as easily
as assembly language or C. In particular, MemMap demonstrates
the ability of Turbo Pascal to manipulate DOS system control
blocks using pointer variables and record types.
Background
----------
The layout of DOS user memory is shown in Figure 2. Following the DOS
system area, each memory block is preceded by a memory control block
(MCB). This MCB stores information on the owner of the block and
the size of the memory block -- described in Figure 3. Once the
initial MCB is found, the next MCB follows the memory block. All
of user memory can be mapped by stepping through, MCB by MCB. The last
MCB is tagged differently than all other MCBs, so a termination condition
is easily recognized. But how is the address of the first MCB found?
The first Memory Control Block can be found by searching through
memory at paragraph boundaries, or by using the undocumented function
call $52 of DOS interrupt $21. MemMap uses the latter approach
to obtain the address of the so-called DOS "List of Lists". At an offset
of -2 in this "List of Lists" is the segment address of the first MCB.
The "Type" of an MCB is determined by observing when certain relationships
exist. If the MCB owner is hex 0000, the block following the MCB is
not allocated and its type is shown as "Free Space". When the first
word of the paragraph following the MCB is hex 20CD (or possibly
27CD), the block type is "Program", if the "owner" field points
to this next paragraph; otherwise, the "owner" is assumed to be the DOS
kernel and the block type is shown as "System". See Figure 4. The block
type is "Environment" when the block's owner has an environment pointer
back to the paragraph following the MCB. When none of the above
relationships hold, the block is assumed to have a "Data" type. (One
TSR that I've found with a "Data" memory block is PC Magazine's
PRN2FILE).
The "Name" of an MCB is determined from the environment block when
possible. In DOS 3.X, the fully-qualified program name follows the
environment value(s) and a special tag word (hex 0001), as shown in
Figure 4. When an environment block does not exist for a program,
or when the program name does not follow the environment block,
a "short" program name (1-8 characters) can be found in the last
half of the MCB -- but only in DOS 4.0. In earlier DOS versions
the name is "<unknown>" in such a case.
Implementation Details for Turbo Pascal 5.0
-------------------------------------------
Pointers are usually used to address dynamic variables created with
the standard Pascal NEW procedure (or Turbo Pascal's GetMem procedure),
but pointers can also be used to manipulate existing data structures,
such as DOS memory blocks. An example of accessing DOS's "List of Lists",
Memory Control Blocks (MCBs) and the Program Segment Prefix (PSP) blocks
using pointer variables is shown in the MemMap Turbo Pascal 5.0 program.
(See Figure 5).
To obtain the address of the DOS "List of Lists", the undocumented
function call $52 of DOS interrupt $21 is needed. The DOS Turbo Pascal
UNIT provides the "Intr" procedure and "Registers" type:
...
VAR r: Registers; {Figure 5, line 57}
...
r.AH := $52; {line 205}
Intr ($21,r); {line 206}
After this DOS interrupt, a pointer to the "List of Lists" is in ES:BX.
At an offset of -2 in the "List of Lists" is the segment address of the
first MCB:
segment := MemW[r.ES:r.BX-2]; {line 207}
where the "MemW" Turbo Pascal "system array" returns the word at the
given segment:offset address. The "MCB" pointer variable is then
defined using the Turbo Pascal "Ptr" procedure:
MCB := Ptr(segment,0); {line 210}
At this point all the variables defined by the MemoryControlBlock TYPE
can be accessed. Typecasting can be used to help calculate the size of
the memory block following the MCB:
bytes := LongInt(MCB^.BlockSize) SHL 4; {line 102}
If the MCB^.BlockOwner is zero, the block is free space. If it is
nonzero, the MCB^.BlockOwner points to a memory block, which is a
valid Program Segment Prefix (PSP) if it starts with the word $20CD
(or possibly $27CD). The PSP pointer is defined by
psp := Ptr(MCB^.BlockOwner,0); {line 109}
A segment pointer to the environment block is at an offset of hex 2C from
the beginning of the PSP, which is defined by psp^.Environment.
Since the environment block must be immediately preceded by an MCB, the
environment MCB is defined by:
MCBenv := Ptr(psp^.Environment-1,0); {line 116}
If the MCB^.BlockOwner is the same as the MCBenv^.BlockOwner,
environment variables follow in ASCIIZ delimited strings (character
strings ending with a $00). A null (zero-length) variable marks the
end of the environment. The program name follows the special
$0001 tag.
Once an MCB and its associated information is displayed, the segment
address of the next MCB is found by the statement:
segment := segment + MCB^.Blocksize + 1; {line 212}
The extra "1" above is needed since the MCB is itself a single
paragraph long.
Contiguous MCBs and memory blocks can be sequentially listed until
the last MCB is found, which is tagged with MCB^.Blocktag = $5A.
A final note: DO NOT use DISPOSE (or FreeMem) to deallocate
a pointer variable that was not allocated using NEW (or GetMem).
Since the DOS control blocks described above are allocated outside
of MemMap, they should not be deallocated by MemMap.
Results
-------
To demonstrate MemMap, several DOS commands and other TSRs were executed
to create a variety of memory control blocks (after booting without
an AUTOEXEC.BAT or CONFIG.SYS present):
APPEND ..
GRAPHICS